/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
/*
* Copyright 2010, Center for Advanced Information Systems,Nanyang Technological University
*
* File name: Modification.java
*
* Abstract: The SPIG based modification process
*
* Current Version:      0.1
* Auther:               Jin Changjiu
* Modified Date:        Feb.11,2010
*
*/
package gblend.modification;

import gblend.exactquery.*;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.Vector;

/**
 *
 * @author ibmuser
 */
public class Modification {

 public void queryModification(QueryEngine qe, int edgelabel, int newqsize)//edgelabel = edgeid+1
{
    ArrayList<SpindleGraph> spindleGraphSet = qe.getSpindleGraphSet();
    for(Iterator itr =  spindleGraphSet.iterator();itr.hasNext();)
    {
         SpindleGraph eg = (SpindleGraph)itr.next();
         if(eg.getId()==edgelabel)//edgeid starts from 0
         {
             itr.remove();
             break;
         }
    }
  
    for(int i = 0;i <spindleGraphSet.size(); i++)
    {
        SpindleGraph eg = spindleGraphSet.get(i);
         if(eg.getId()>edgelabel)
         {
            //rebuit eg
            SpindleGraph neweg = rebuildSgraph(eg, edgelabel);
            spindleGraphSet.add(i, neweg);
            spindleGraphSet.remove(i+1);
         }
    }

    //update feature table
    HashMap<Integer, ArrayList<SNode>> featureTable = qe.getFeatureTable();
    featureTable.remove(newqsize);

    for(int i = newqsize-1; i>=newqsize-qe.getSigma(); i--)
    {
        if(featureTable.containsKey(i))
        {
            ArrayList<SNode>nodeset = featureTable.get(i);
            for(Iterator itr=nodeset.iterator(); itr.hasNext();)
            {
                SNode tmpnode = (SNode)itr.next();
                if(tmpnode.getEdgelabelSet().contains(edgelabel))
                {
                    itr.remove();
                }
            }
        }
    }

}

//rebuild SPIG set after modification
public SpindleGraph rebuildSgraph(SpindleGraph eg, int edgelabel)
{
    SpindleGraph neweg = null;
    int endnodeid = eg.getSize()-1;
    //look for the largest node without edgelabel
    for(int i=0; i<endnodeid;i++)
    {
        if(eg.getEdge(i, endnodeid)==1)
        {
            SNode tmpnode = eg.getNode(i);
            HashSet<Integer> edgelabelset = new HashSet<Integer>();
            for(int m = 0; m< tmpnode.getNnum(); m++)
            {
                for(int n = 0;n< tmpnode.getNnum(); n++)
                {
                  if(tmpnode.getEdge(m,n)>0)
                     edgelabelset.add(tmpnode.getEdge(m,n));
                }
            }
            if(!edgelabelset.contains(edgelabel))
            {
                eg.dsf(i);
                tmpnode.setSucc(i);//add itself
                neweg = updateSgraph(eg, tmpnode.getSucc());
                break;
            }
        }
    }

    return neweg;

}

//update the SPIG by deleting some nodes
public SpindleGraph updateSgraph(SpindleGraph oldeg, ArrayList<Integer>nodeset)
{
    HashMap<Integer, Integer> idmap = new HashMap<Integer, Integer>();
    SpindleGraph neweg = new SpindleGraph(nodeset.size());
    int k = 0;
    for(int i=0; i<oldeg.getSize();i++)
    {
        if(nodeset.contains(i))
        {
            neweg.addnode(oldeg.getNode(i));
            idmap.put(oldeg.getNode(i).getGraphid()[0], k++);
        }
    }

    for(int i=0; i<oldeg.getSize();i++)
    {
        for(int j=0; j<oldeg.getSize();j++)
        {
            if(oldeg.getEdge(i, j)==1&&nodeset.contains(i)&&nodeset.contains(j))
            {
                neweg.addEdge(idmap.get(i), idmap.get(j));
            }
        }
    }

    neweg.setId(oldeg.getId());
    return neweg;

}

//calculate the modification suggestion
public int modifySuggestion(QueryEngine qe)
{
    ArrayList<SpindleGraph> spindleGraphSet = qe.getSpindleGraphSet();
    System.out.println("Modification Suggestion:");
    SNode newquery = null;
    MaxCandidate maxNode = new MaxCandidate();
    SpindleGraph exgraph = null;

    if(spindleGraphSet.size()>1)
    {
        exgraph = spindleGraphSet.get(spindleGraphSet.size()-2);
    }//the spindle graph buit in the previous step
    else
    {
        exgraph = spindleGraphSet.get(0);
    }

    SNode exnode = exgraph.getNode(exgraph.getSize()-1);//the last node in the previous spindle graph
    qe.retrieveIdset(exnode);//get its idlist
    maxNode.setNodeAtt(-1, qe.getCandidateIds().size());

    SpindleGraph newExgraph = spindleGraphSet.get(spindleGraphSet.size()-1);//the new spindle graph
    for(int i = 0; i< newExgraph.getSize()-1; i++)
    {
        if(newExgraph.getEdge(i, newExgraph.getSize()-1)==1)//the |q|-1th level
        {
            qe.retrieveIdset(newExgraph.getNode(i));
           
            if(qe.getCandidateIds().size() > maxNode.getNodeSize())
            {
               maxNode.setNodeAtt(i, qe.getCandidateIds().size());
            }
        }
    }

    //calculate the suggested edge
    if(maxNode.getNodeId()==-1)
    {
        newquery = exnode;
    }
    else
    {
        newquery = newExgraph.getNode(maxNode.getNodeId());
    }
   
   Vector<Integer> allEdges = newExgraph.getNode(newExgraph.getSize()-1).getEdgelabelSet();//edges in query
    Vector<Integer> edgeSet = new Vector<Integer>();
    edgeSet.addAll(allEdges);
    edgeSet.removeAll(newquery.getEdgelabelSet());//remove all the edges in newquery
    System.out.println("Delete Edge: "+edgeSet.firstElement()+" Candidate Size: "+maxNode.getNodeSize());
    return edgeSet.firstElement();


}



}
